import axios from 'axios'
import type { AxiosRequestConfig, Method } from 'axios' // 确保导入 axios 类型
import { useUserStore } from '@/stores'
import { ElMessage, ElNotification, ElMessageBox } from 'element-plus'
import { HttpStatus } from '@/enums/RespEnum'
import { errorCode } from '@/utils/errorCode'
import {
  encryptBase64,
  encryptWithAes,
  generateAesKey,
  decryptWithAes,
  decryptBase64
} from '@/utils/crypto'
import { encrypt, decrypt } from '@/utils/jsencrypt'
import router from '@/router'
// 1. 新axios实例，基础配置
const encryptHeader = 'encrypt-key'
// 是否显示重新登录
export const isRelogin = { show: false }
//本地
const baseURL = import.meta.env.DEV
  ? import.meta.env.VITE_DPING_DEV
  : import.meta.env.VITE_DPING_POR

axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID

export const globalHeaders = () => {
  const store = useUserStore()
  return {
    Authorization: `Bearer ${store.token}`,
    clientid: import.meta.env.VITE_APP_CLIENT_ID
  }
}

const instance = axios.create({
  baseURL,
  timeout: 10000
})

// 2. 请求拦截器，携带token
instance.interceptors.request.use(
  (config) => {
    const store = useUserStore()
    if (store?.token) {
      config.headers.Authorization = `Bearer ${store.token}`
    }
    // 是否需要加密
    const isEncrypt = config.headers?.isEncrypt === 'true'
    if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
      // 当开启参数加密
      if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
        // 生成一个 AES 密钥
        const aesKey = generateAesKey()
        config.headers[encryptHeader] = encrypt(encryptBase64(aesKey))
        config.data =
          typeof config.data === 'object'
            ? encryptWithAes(JSON.stringify(config.data), aesKey)
            : encryptWithAes(config.data, aesKey)
      }
    }
    // FormData数据去请求头Content-Type
    if (config.data instanceof FormData) {
      delete config.headers['Content-Type']
    }
    return config
  },
  (err) => Promise.reject(err)
)

// 3. 响应拦截器，剥离无效数据，401拦截
instance.interceptors.response.use(
  (res) => {
    // if (res.data.code !== 200) {
    //   ElMessage.error(res.data.msg)
    // } else if (res.data.code == 401) {
    //   router.push('/login')
    // }
    if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
      // 加密后的 AES 秘钥
      const keyStr = res.headers[encryptHeader]
      // 加密
      if (keyStr != null && keyStr != '') {
        const data = res.data
        // 请求体 AES 解密
        const base64Str = decrypt(keyStr)
        // base64 解码 得到请求头的 AES 秘钥
        const aesKey = decryptBase64(base64Str.toString())
        // aesKey 解码 data
        const decryptData = decryptWithAes(data, aesKey)
        // 将结果 (得到的是 JSON 字符串) 转为 JSON
        res.data = JSON.parse(decryptData)
      }
    }
    // 未设置状态码则默认成功状态
    const code = res.data.code || HttpStatus.SUCCESS
    // 获取错误信息
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    // 二进制数据则直接返回
    if (
      res.request.responseType === 'blob' ||
      res.request.responseType === 'arraybuffer'
    ) {
      return res.data
    }
    if (code === 401) {
      if (!isRelogin.show) {
        isRelogin.show = true
        ElMessageBox.confirm(
          '登录状态已过期，您可以继续留在该页面，或者重新登录',
          '系统提示',
          {
            confirmButtonText: '重新登录',
            cancelButtonText: '取消',
            type: 'warning'
          }
        )
          .then(() => {
            isRelogin.show = false
            sessionStorage.clear()
            localStorage.clear()
            router.push('/login')
          })
          .catch(() => {
            isRelogin.show = false
          })
      }
      return Promise.reject('无效的会话，或者会话已过期，请重新登录。')
    } else if (code === HttpStatus.SERVER_ERROR) {
      ElMessage({ message: msg, type: 'error' })
      return Promise.reject(new Error(msg))
    } else if (code === HttpStatus.WARN) {
      ElMessage({ message: msg, type: 'warning' })
      return Promise.reject(new Error(msg))
    } else if (code !== HttpStatus.SUCCESS) {
      ElNotification.error({ title: msg })
      return Promise.reject('error')
    } else {
      return Promise.resolve(res.data)
    }
    // return res.data
  },
  (err) => {
    if (err.response) {
      ElMessage.error(err)
    }
    return Promise.reject(err)
  }
)

export { baseURL, instance }
// 这个需要替换axsio.request默认的响应成功后的结果类型
// 之前是：传 { name: string } 然后res是   res = { data: { name: string } }
// 但现在：在响应拦截器中返回了 res.data  也就是将来响应成功后的结果，和上面的类型一致吗？
// 所以要：request<数据类型，数据类型>() 这样才指定了 res.data 的类型
// 但是呢：后台返回的数据结构相同，所以可以抽取相同的类型
type Data<T> = {
  rows: any
  total: number
  token: string
  code: number
  msg: string
  data: T
}
// 4. 请求工具函数
export const request = <T>(
  url: string,
  method: Method = 'get',
  submitData?: object,
  headers?: object,
  responseType?: AxiosRequestConfig['responseType'] // 使用 axios 的 ResponseType
) => {
  return instance.request<T, Data<T>>({
    url,
    method,
    [method.toLowerCase() === 'get' ? 'params' : 'data']: submitData,
    headers,
    responseType // 添加 responseType 配置
  })
  // .then((res) => {
  //   if (res.code == 200) {
  //     return res // 返回成功的数据
  //   } else {
  //     ElMessage.error(res.msg) // 抛出错误
  //   }
  // })
  // .catch((err) => {
  //   ElMessage.error(err)
  // })
}
